/*
 * Albareth - an action roleplaying game.
 * Copyright (C) 2008 Jens Anuth
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 *   02110-1301, USA.
 * 
 * $Id: MobileFactory.java 49 2008-05-17 02:35:15Z jens464 $
*/
package albareth.core.entity;

import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Vector;

import albareth.core.GameEffect;
import albareth.core.action.Spell;
import albareth.core.action.SpellMagicMissile;
import albareth.core.action.SpellShootProjectile;
import albareth.core.brain.Brain;
import albareth.core.brain.DomesticAnimalBrain;
import albareth.core.brain.HumanoidBrain;
import albareth.core.brain.MonsterBrain;
import albareth.core.brain.UndeadBrain;
import albareth.core.entity.template.MobileTemplate;
import albareth.frontend.Resources;
import albareth.frontend.Tile;
import albareth.frontend.TileCollection;
import frosch.util.Log;
import frosch.util.Range;
import frosch.util.WeightedSet;

public class MobileFactory
{
    public static final String SET_FARM_ANIMALS = "set_farm_animals";
    public static final String SET_TOWN_ANIMALS = "set_town_animals";
    public static final String SET_FOREST_ANIMALS = "set_forest_animals";
    public static final String SET_MONSTERS = "set_monsters";
    
    private static MobileFactory _instance = null;
    
    /** WeightedSets of MobileTemplates */
    private Map _mobileTemplateSets = new HashMap();
    
    /** List of all monster MobileTemplates */
    private LinkedList _allMonsters = new LinkedList();

    
    private MobileFactory()
    {
        loadPredefinedSets();
    }
    
    public static MobileFactory getInstance()
    {
        if (_instance == null) {
            _instance = new MobileFactory();
        }
        return _instance;
    }
    
    public MobileTemplate getRandomTemplate(String setId)
    {
        WeightedSet set = (WeightedSet)_mobileTemplateSets.get(setId);
        if (set == null) {
            throw new UnknownStringIdException(
                    "NPC template set id unknown: " + setId
            );
        }
        return (MobileTemplate)set.randomElement();
    }
    
    /**
     * Returns all monster templates with level range
     * contained in the given levelRange.
     */
    public Vector getAllMonsterTemplates(Range levelRange)
    {
        Vector templates = new Vector();
        for (Iterator it = _allMonsters.iterator(); it.hasNext(); )
        {
            MobileTemplate mobTpl = (MobileTemplate)it.next();
            Range mobRange = mobTpl.getLevelRange();
            if (levelRange.getMin() <= mobRange.getMin() &&
                    levelRange.getMax() >= mobRange.getMax())
            {
                templates.add(mobTpl);
            }
        }
        
        if (templates.isEmpty()) {
            Log.warn("No Monster Templates found in level range " + levelRange);
        }

        return templates;
    }


    public Mobile createRandomMobile(String setId)
    {
        MobileTemplate templ = getRandomTemplate(setId);
        return templ.create();
    }
    
    private void loadPredefinedSets()
    {
        //XXX: xml config
        
        WeightedSet farmAnimals = new WeightedSet();
        _mobileTemplateSets.put(SET_FARM_ANIMALS, farmAnimals);
        WeightedSet forestAnimals = new WeightedSet();
        _mobileTemplateSets.put(SET_FOREST_ANIMALS, forestAnimals);
        WeightedSet townAnimals = new WeightedSet();
        _mobileTemplateSets.put(SET_TOWN_ANIMALS, townAnimals);

        //farm animals:
        MobileTemplate chicken = createAnimalTpl("Chicken", TileCollection.CHICKEN, 1);
        MobileTemplate sheep = createAnimalTpl("Sheep", TileCollection.SHEEP, 1);
        MobileTemplate cow = createAnimalTpl("Cow", TileCollection.COW, 1);
        MobileTemplate pig = createAnimalTpl("Pig", TileCollection.PIG, 1);
        MobileTemplate horse = createAnimalTpl("Horse", TileCollection.HORSE, 1);
        farmAnimals.add(chicken, 1);
        farmAnimals.add(sheep, 1);
        farmAnimals.add(cow, 1);
        farmAnimals.add(pig, 1);
        farmAnimals.add(horse, 1);
        
        //town animals:
        MobileTemplate cat = createAnimalTpl("Cat", TileCollection.CAT, 1);
        MobileTemplate dog = createAnimalTpl("Dog", TileCollection.DOG, 1);
        MobileTemplate rat = createAnimalTpl("Rat", TileCollection.RAT, 1);
        townAnimals.add(cat, 1);
        townAnimals.add(dog, 1);
        townAnimals.add(rat, 1);

        //forest animals:
        MobileTemplate stag = createAnimalTpl("Deer", TileCollection.DEER, 1);
        MobileTemplate wolf = createAnimalTpl("Wolf", TileCollection.WOLF, 2);
        MobileTemplate bear = createAnimalTpl("Bear", TileCollection.BEAR, 3);
        MobileTemplate rabbit = createAnimalTpl("Rabbit", TileCollection.RABBIT, 1);
        forestAnimals.add(stag, 1);
        forestAnimals.add(wolf, 1);
        forestAnimals.add(bear, 1);
        forestAnimals.add(rabbit, 1);

        
        
        
        //some spells for the monsters:
        
        SpellShootProjectile hurlBones = new SpellShootProjectile(
                "Bone", TileCollection.BONE, null, true, new Range(1,6),
                GameEffect.FLY_INFINITE|GameEffect.HIT_ENEMIES_ON_PATH
        );
        hurlBones.setHitSoundId(Resources.SOUND_RANGED_HIT);
        hurlBones.setShootSoundId(Resources.SOUND_HURL);
        hurlBones.setSpeed(3.5f);
        hurlBones.setCastingDuration(1500);
        hurlBones.setCooldownDuration(6000);

        SpellShootProjectile throwStones = new SpellShootProjectile(
                "Stone", TileCollection.STONE, null, false, new Range(1,6), 0
        );
        throwStones.setHitSoundId(Resources.SOUND_RANGED_HIT);
        throwStones.setShootSoundId(Resources.SOUND_THROW);
        throwStones.setSpeed(3.5f);
        throwStones.setCastingDuration(1500);
        throwStones.setCooldownDuration(6000);

        SpellShootProjectile throwSpear = new SpellShootProjectile(
                "Stone", TileCollection.THROWING_SPEAR, null, false, new Range(1,6),
                GameEffect.FLY_INFINITE|GameEffect.HIT_ENEMIES_ON_PATH|GameEffect.HIT_ITEMS_ON_PATH
        );
        throwSpear.setHitSoundId(Resources.SOUND_RANGED_HIT);
        throwSpear.setShootSoundId(Resources.SOUND_THROW);
        throwSpear.setSpeed(5.5f);
        throwSpear.setCastingDuration(1500);
        throwSpear.setCooldownDuration(6000);

        
        SpellShootProjectile spitSlime = new SpellShootProjectile(
                "Slime", null, Resources.EFFECT_POISON_SHOOT, false,
                new Range(1,6), 0
        );
        spitSlime.setHitSoundId(Resources.SOUND_SLIME);
        spitSlime.setShootSoundId(Resources.SOUND_SLIME);
        spitSlime.setSpeed(4.5f);
        spitSlime.setCastingDuration(1500);
        spitSlime.setCooldownDuration(6000);
        
        Spell missile = new SpellMagicMissile();
        missile.setCastingDuration(1000);
        missile.setCooldownDuration(8000);


        
        
        
        
        
        
        
        //monsters:
        MobileTemplate slug = createTpl("Slug", TileCollection.SLUG, new MonsterBrain(), new Range(1, 1));
        _allMonsters.add(slug);
        MobileTemplate snake = createTpl("Snake", TileCollection.SNAKE, new MonsterBrain(), new Range(1,1));
        snake.addSpell(spitSlime);
        _allMonsters.add(snake);
        MobileTemplate slime = createTpl("Slime", TileCollection.SLIME, new MonsterBrain(), new Range(1,1));
        slime.addSpell(spitSlime);
        _allMonsters.add(slime);
        
        MobileTemplate spider = createTpl("Giant Spider", TileCollection.SPIDER, new MonsterBrain(), new Range(1,2));                    
        _allMonsters.add(spider);
        MobileTemplate larva = createTpl("Giant Larva", TileCollection.GIANT_LARVA, new MonsterBrain(), new Range(1,2));
        larva.addSpell(spitSlime);
        _allMonsters.add(larva);
        MobileTemplate mite = createTpl("Giant Mite", TileCollection.GIANT_MITE, new MonsterBrain(), new Range(1,2));
        _allMonsters.add(mite);
        MobileTemplate skeleton = createTpl("Skeleton", TileCollection.SKELETON, new UndeadBrain(), new Range(2,2));
        skeleton.addSpell(hurlBones);
        _allMonsters.add(skeleton);
        MobileTemplate headless = createTpl("Headless", TileCollection.HEADLESS, new UndeadBrain(), new Range(2,2));
        _allMonsters.add(headless);
        MobileTemplate zombie = createTpl("Zombie", TileCollection.ZOMBIE, new UndeadBrain(), new Range(2,2));
        _allMonsters.add(zombie);
        MobileTemplate goblin = createTpl("Goblin", TileCollection.GOBLIN, new HumanoidBrain(), new Range(2,3));
        goblin.addSpell(throwStones);
        _allMonsters.add(goblin);
        MobileTemplate bee = createTpl("Giant Bee", TileCollection.GIANT_BEE, new MonsterBrain(), new Range(3,3));
        _allMonsters.add(bee);
        MobileTemplate mosquito = createTpl("Giant Mosquito", TileCollection.MOSQUITO, new MonsterBrain(), new Range(3,3));
        _allMonsters.add(mosquito);
        MobileTemplate bullfrog = createTpl("Bullfrog", TileCollection.BULLFROG, new MonsterBrain(), new Range(3,3));
        goblin.addSpell(spitSlime);
        _allMonsters.add(bullfrog);
        MobileTemplate fungus = createTpl("Fungus", TileCollection.FUNGUS, new MonsterBrain(), new Range(3,3));
        _allMonsters.add(fungus);
        MobileTemplate lizardman = createTpl("Lizardman", TileCollection.LIZARDMAN_SPEAR, new HumanoidBrain(), new Range(3,4));
        lizardman.addSpell(throwSpear);
        _allMonsters.add(lizardman);
        MobileTemplate trog = createTpl("Trog", TileCollection.TROGLODYTE_CLUB, new HumanoidBrain(), new Range(3,4));
        _allMonsters.add(trog);
        MobileTemplate lizardmanSword = createTpl("Lizardman", TileCollection.LIZARDMAN_SWORD, new HumanoidBrain(), new Range(3,4));
        _allMonsters.add(lizardmanSword);
        MobileTemplate trogSpear = createTpl("Trog", TileCollection.TROGLODYTE_SPEAR, new HumanoidBrain(), new Range(3,4));
        trogSpear.addSpell(throwSpear);
        _allMonsters.add(trogSpear);
        MobileTemplate alligator = createTpl("Alligator", TileCollection.ALLIGATOR, new MonsterBrain(), new Range(3,4));
        _allMonsters.add(alligator);
        MobileTemplate scorpion = createTpl("Scorpion", TileCollection.SCORPION, new MonsterBrain(), new Range(3,4));
        _allMonsters.add(scorpion);
        MobileTemplate ghost = createTpl("Ghost", TileCollection.GHOST, new UndeadBrain(), new Range(3,5));
        _allMonsters.add(ghost);
        MobileTemplate bully = createTpl("Bullywug", TileCollection.BULLYWUG, new HumanoidBrain(), new Range(4,4));
        bully.addSpell(throwSpear);
        _allMonsters.add(bully);
        MobileTemplate bullyAxe = createTpl("Bullywug", TileCollection.BULLYWUG_AXE, new HumanoidBrain(), new Range(4,4));
        _allMonsters.add(bullyAxe);
        MobileTemplate goblinArcher = createTpl("Goblin Archer", TileCollection.GOBLIN_ARCHER, new HumanoidBrain(), new Range(4,5));
        _allMonsters.add(goblinArcher);
        MobileTemplate spectre = createTpl("Spectre", TileCollection.SPECTRE, new UndeadBrain(), new Range(4,5));
        _allMonsters.add(spectre);
        MobileTemplate bugbear = createTpl("Bugbear", TileCollection.BUGBEAR, new HumanoidBrain(), new Range(5,5));
        bugbear.addSpell(throwStones);
        _allMonsters.add(bugbear);
        MobileTemplate fungusMan = createTpl("Fungus Man", TileCollection.FUNGUS_MAN, new MonsterBrain(), new Range(5,6));
        _allMonsters.add(fungusMan);
        MobileTemplate skeletonArcher = createTpl("Skeleton Archer", TileCollection.SKELETON_ARCHER, new UndeadBrain(), new Range(5,6));
        skeletonArcher.addSpell(hurlBones);
        _allMonsters.add(skeletonArcher);
        MobileTemplate skull = createTpl("Floating Skull", TileCollection.FLOATING_SKULL, new UndeadBrain(), new Range(5,6));
        skull.addSpell(hurlBones);
        _allMonsters.add(skull);
        MobileTemplate harpy = createTpl("Harpy", TileCollection.HARPY, new MonsterBrain(), new Range(6,7));
        _allMonsters.add(harpy);
        MobileTemplate corpser = createTpl("Corpser", TileCollection.CORPSER, new MonsterBrain(), new Range(6,8));
        _allMonsters.add(corpser);
        MobileTemplate skeletalKnight = createTpl("Skeletal Knight", TileCollection.SKELETON_KNIGHT, new UndeadBrain(), new Range(7,8));
        skeletalKnight.addSpell(hurlBones);
        _allMonsters.add(skeletalKnight);
        MobileTemplate phantom = createTpl("Phantom", TileCollection.PHANTOM, new UndeadBrain(), new Range(7,8));
        _allMonsters.add(phantom);
        MobileTemplate faerie = createTpl("Faerie", TileCollection.FAERIE, new MonsterBrain(), new Range(8,9));
        faerie.addSpell(missile);
        _allMonsters.add(faerie);
        MobileTemplate satyr = createTpl("Satyr", TileCollection.SATYR, new MonsterBrain(), new Range(9,10));
        _allMonsters.add(satyr);
        MobileTemplate treant = createTpl("Treant", TileCollection.TREANT, new MonsterBrain(), new Range(10,11));
        _allMonsters.add(treant);
        MobileTemplate earthElem = createTpl("Earth Elemental", TileCollection.EARTH_ELEMENTAL, new MonsterBrain(), new Range(11,11));           
        _allMonsters.add(earthElem);
        MobileTemplate airElem = createTpl("Air Elemental", TileCollection.AIR_ELEMENTAL, new MonsterBrain(), new Range(11,12));             
        _allMonsters.add(airElem);
        MobileTemplate fireElem = createTpl("Fire Elemental", TileCollection.FIRE_ELEMENTAL, new MonsterBrain(), new Range(11,12));            
        _allMonsters.add(fireElem);
        MobileTemplate waterElem = createTpl("Water Elemental", TileCollection.WATER_ELEMENTAL, new MonsterBrain(), new Range(11,12));
        _allMonsters.add(waterElem);
        MobileTemplate imp = createTpl("Imp", TileCollection.IMP, new MonsterBrain(), new Range(11,13));
        _allMonsters.add(imp);
        MobileTemplate wisp = createTpl("Will o Wisp", TileCollection.WILL_O_WISP, new MonsterBrain(), new Range(13,13));
        wisp.addSpell(missile);
        _allMonsters.add(wisp);
        MobileTemplate sorcerer = createTpl("Elven Sorcerer", TileCollection.ELVEN_WIZARD, new HumanoidBrain(), new Range(13,14));
        sorcerer.addSpell(missile);
        _allMonsters.add(sorcerer);
        MobileTemplate minotaur = createTpl("Minotaur", TileCollection.MINOTAUR, new HumanoidBrain(), new Range(14,14));                  
        _allMonsters.add(minotaur);
        MobileTemplate naga = createTpl("Naga", TileCollection.NAGA, new MonsterBrain(), new Range(15,16));
        naga.addSpell(spitSlime);
        _allMonsters.add(naga);
        MobileTemplate beholder = createTpl("Beholder", TileCollection.BEHOLDER, new MonsterBrain(), new Range(16,17));                  
        _allMonsters.add(beholder);
        MobileTemplate daemon = createTpl("Daemon", TileCollection.DAEMON, new MonsterBrain(), new Range(18,19));                                          
        _allMonsters.add(daemon);
        MobileTemplate dragon = createTpl("Dragon", TileCollection.DRAGON, new MonsterBrain(), new Range(21, 21));                    
        _allMonsters.add(dragon);
        //Action fireball = new ActionFireball();
        //fireball.setCooldownDuration(4000);
        //zombie.addAction(fireball);
        //_mobileTemplates.put("zombie", zombie);
    }

    private MobileTemplate createTpl(String name, Tile tile, Brain brain, Range levelRange)
    {
        MobileTemplate tpl = new MobileTemplate(name, tile);
        tpl.setBrain(brain);
        tpl.setLevelRange(levelRange);
        return tpl;
    }

    private MobileTemplate createAnimalTpl(String name, Tile tile, int level)
    {
        return createTpl(
                name, tile,
                new DomesticAnimalBrain(),
                new Range(level, level)
        );
    }

    

    
    
}
